﻿/**
@file
@brief  使用宏来实现COM接口的委托类CComSink
@version 2005-12-06 xcong created
*/

#pragma once

#ifdef WIN32
#include <atlbase.h>
#endif
#include <atlcom.h>
#include "Util.h"
#include "ComSinkPtr.h"


class FWeakCallback
{
public:
    virtual ~FWeakCallback() {}
};

#define __DECLARE_COMSINK_BEGIN(CComSink, IComSink, IImpl) \
template <class CHost> \
class __multiple_inheritance CComSink; \
\
template <class CHost> \
class CComSink##Ptr : public CComSinkPtr<CComSink<CHost> > \
{ \
public: \
	CComSink##Ptr(CHost* pHost) : CComSinkPtr<CComSink<CHost> >(pHost) \
	{} \
	CComSink##Ptr(const AsyncTask::WeakPtr<CHost>& pHost) : CComSinkPtr<CComSink<CHost> >(pHost) \
	{} \
	virtual HRESULT FinalConstruct(){return S_OK;};\
	virtual void FinalRelease() {return;};\
}; \
\
template <class CHost> \
class CComSink:	public CComObjectRootEx<CComMultiThreadModel>, \
				public IImpl \
{ \
	friend class CComSinkPtr<CComSink<CHost> >; \
public: \
	typedef CHost CHostType;\
	CComSink(CHost* pHost) \
		:m_pHost(pHost)\
	{ \
        _AtlInitialConstruct(); \
		memset((BYTE*)&m_pWeakHost + sizeof(m_pWeakHost), 0, sizeof(*this) - ((BYTE*)&m_pWeakHost - (BYTE*)this) - sizeof(m_pWeakHost)); \
	} \
	CComSink(const AsyncTask::WeakPtr<CHost>& pHost) \
		:m_pWeakHost(pHost), m_pHost(NULL) \
	{ \
        _AtlInitialConstruct(); \
		memset((BYTE*)&m_pWeakHost + sizeof(m_pWeakHost), 0, sizeof(*this) - ((BYTE*)&m_pWeakHost - (BYTE*)this) - sizeof(m_pWeakHost)); \
	} \
	~CComSink() \
	{ \
		UnhookAll(); \
		m_pHost = NULL;\
		} \
	virtual HRESULT FinalConstruct(){return S_OK;};\
	virtual void FinalRelease() {return;};\
\
public: \
	void UnhookAll() \
	{ \
		for (BYTE * p = (BYTE*)&m_pWeakHost + sizeof(m_pWeakHost); p < (BYTE*)this + sizeof(*this); p += sizeof(FWeakCallback*)) \
		{ \
			FWeakCallback* pF = *((FWeakCallback**)p); \
			delete pF; \
		} \
		memset((BYTE*)&m_pWeakHost + sizeof(m_pWeakHost), 0, sizeof(*this) - ((BYTE*)&m_pWeakHost - (BYTE*)this) - sizeof(m_pWeakHost)); \
	} \
\
private: \
	CHost*	m_pHost; \
	AsyncTask::WeakPtr<CHost>	m_pWeakHost; \
\
private: \
	CComSink& operator=(const CComSink& rhs); \
	CComSink(const CComSink& rhs); 

/// @ingroup ov_ComSink
#define __DECLARE_COMSINK_INTERFACE_BEGIN(CComSink) \
public: \
	BEGIN_COM_MAP(CComSink<CHost>)

/// @ingroup ov_ComSink
#define __IMPLEMENT_COMSINK_INTERFACE(IInterface) \
	COM_INTERFACE_ENTRY(IInterface)

/// @ingroup ov_ComSink
#define __DECLARE_COMSINK_INTERFACE_END() \
	END_COM_MAP()

/// @ingroup ov_ComSink

#define __IMPLEMENT_COMSINK_FUNCTION(func, params, values) \
public: \
	typedef HRESULT (CHost::*MF##func)params; \
\
	template <class T, class Method, class ParamEx, class Callback> \
	class func##Method : public Callback \
	{ \
	public: \
		func##Method(const AsyncTask::WeakPtr<T>& obj, Method meth, const ParamEx& paramsEx) \
			: obj_(obj), meth_(meth), paramsEx_(paramsEx) {} \
		virtual HRESULT operator() params \
		{ \
			if (obj_) \
			{ \
				RunnableMethodTraits<T> traits_; \
				traits_.RetainCallee(obj_); \
				HRESULT hr = ComDispatchToMethod(obj_.get(), meth_, CombineTuple(MakeTuple values, paramsEx_)); \
				traits_.ReleaseCallee(obj_); \
				return hr; \
			} \
			return S_OK; \
		} \
	private: \
		AsyncTask::WeakPtr<T> obj_; \
		Method meth_; \
		ParamEx paramsEx_;\
		DISALLOW_COPY_AND_ASSIGN(func##Method); \
	}; \
	template <class T, class Callback> \
	class func##RawMethod : public Callback \
	{ \
	public: \
		func##RawMethod(T* pHost, MF##func meth) \
			: pHost_(pHost), meth_(meth) {} \
		virtual HRESULT operator() params \
		{ \
			return ((pHost_)->*(meth_))values; \
		} \
	private: \
		T* pHost_; \
		MF##func meth_; \
		DISALLOW_COPY_AND_ASSIGN(func##RawMethod); \
	}; \
	class F##func : public FWeakCallback \
	{ \
	public: \
		virtual HRESULT operator() params = 0; \
	}; \
	template <class Method, class ParamsEx> \
	F##func* New##func##Method(Method meth, ParamsEx paramsEx) \
	{ \
		return new func##Method<CHost, Method, ParamsEx, F##func> \
			(m_pWeakHost, meth, paramsEx); \
	} \
	void Hook_##func(F##func* pf##func) \
	{ \
		F##func* funcTemp = m_pf##func;	\
		m_pf##func = pf##func; \
		delete funcTemp; \
	} \
	void Hook_##func(MF##func pmf##func) \
	{ \
		F##func* funcTemp = m_pf##func;	\
		m_pf##func = new func##RawMethod<CHost, F##func>(m_pHost, pmf##func); \
		delete funcTemp; \
	} \
	void Unhook_##func() \
    { \
        Lock(); \
		delete m_pf##func; \
        m_pf##func	= NULL; \
        Unlock(); \
	} \
	STDMETHOD(func) params \
	{ \
		if ((m_pHost==NULL /*|| (DWORD)m_pHost>=0x80000000*/) && !m_pWeakHost) \
		{ \
			TXASSERT_COND( CTXString(_T("ComSink使用不当:")) + CTXString(tagEN(), typeid(CHost).name()) + CTXString(_T("没有把ComSink从Source中移除"))); \
			return E_UNEXPECTED; \
		} \
        HRESULT hRet = E_NOTIMPL; \
        Lock(); \
        do \
        { \
            if (m_pHost /*&& (DWORD)m_pHost<0x80000000*/ && m_pf##func) \
		    { \
                hRet = (*m_pf##func) values; \
			    break; \
		    } \
		    if (m_pWeakHost && m_pf##func) \
		    { \
			    hRet = (*m_pf##func) values; \
                break; \
		    } \
		    if (m_pWeakHost.rawget()) \
		    { \
			    if (m_pWeakHost) \
				    hRet = E_NOTIMPL; \
			    else \
				    hRet = E_UNEXPECTED; \
		    } \
        } while (false); \
        Unlock(); \
		return hRet;	\
	} \
private: \
	F##func* m_pf##func = nullptr;

/// @ingroup ov_ComSink
#define __DECLARE_COMSINK_END() };

/// @ingroup ov_ComSink
#define DECLARE_COMSINK_BEGIN(CComSink, IComSink) \
	__DECLARE_COMSINK_BEGIN(CComSink, IComSink, IComSink) \
	__DECLARE_COMSINK_INTERFACE_BEGIN(CComSink) \
		__IMPLEMENT_COMSINK_INTERFACE(IComSink) \
	__DECLARE_COMSINK_INTERFACE_END()

/// @ingroup ov_ComSink
#define IMPLEMENT_COMSINK_FUNCTION(func, params, values) __IMPLEMENT_COMSINK_FUNCTION(func, params, values)

/// @ingroup ov_ComSink
#define DECLARE_COMSINK_END() __DECLARE_COMSINK_END()





/// @ingroup ov_ComSink
#define DECLARE_INHERIT_COMSINK_BEGIN(CComSink, IComSink) __DECLARE_COMSINK_BEGIN(CComSink, IComSink, IComSink)

/// @ingroup ov_ComSink
#define DECLARE_INHERIT_COMSINK_INTERFACE_BEGIN(CComSink) __DECLARE_COMSINK_INTERFACE_BEGIN(CComSink)

/// @ingroup ov_ComSink
#define IMPLEMENT_INHERIT_COMSINK_INTERFACE(IInterface) __IMPLEMENT_COMSINK_INTERFACE(IInterface) 

/// @ingroup ov_ComSink
#define DECLARE_INHERIT_COMSINK_INTERFACE_END() __DECLARE_COMSINK_INTERFACE_END()

/// @ingroup ov_ComSink
#define IMPLEMENT_INHERIT_COMSINK_FUNCTION(func, params, values) __IMPLEMENT_COMSINK_FUNCTION(func, params, values)

/// @ingroup ov_ComSink
#define DECLARE_INHERIT_COMSINK_END() __DECLARE_COMSINK_END()

